package com.example.friend.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.example.api.domain.JudgeSubmitDTO;
import com.example.core.enums.QuestResultCode;
import com.example.core.utils.StringUtils;
import com.example.core.utils.UUIDUtils;
import com.example.friend.domain.Exam;
import com.example.friend.domain.Question;
import com.example.friend.domain.UserSubmit;
import com.example.friend.domain.dto.UserSubmitDTO;
import com.example.friend.domain.vo.CaseJudgeResult;
import com.example.friend.domain.vo.QuestionESVO;
import com.example.friend.domain.vo.QuestionResult;
import com.example.friend.elasticsearch.QuestionRepository;
import com.example.friend.manger.ExamCacheManager;
import com.example.friend.mapper.QuestionMapper;
import com.example.friend.mapper.UserSubmitMapper;
import com.example.friend.rabbitmq.JudgeProducer;
import com.example.friend.service.IUserSubmitService;
import com.example.scurity.exception.ServiceException;
import com.example.scurity.utils.SecurityUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
@Slf4j
public class UserSubmitServiceImpl extends ServiceImpl<UserSubmitMapper, UserSubmit> implements IUserSubmitService {

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private JudgeProducer judgeProducer;

    @Autowired
    private ExamCacheManager examCacheManager;

    @Autowired
    private QuestionRepository questionRepository;

//    @Autowired
//    private RemoteJudgeService remoteJudgeService;

    @Override
    public boolean submit(UserSubmitDTO userSubmitDTO) {
        //从缓存中获取竞赛信息
        Long examId = userSubmitDTO.getExamId();
        if (examId != null) {
            Exam exam = examCacheManager.selectExamBaseInfo(examId);
            if (exam == null) {
                log.error("用户提交竞赛id:{},未获取到竞赛信息", examId);
                throw new ServiceException("竞赛信息异常常，联系管理员");
            }
            if (exam.getEndTime().isBefore(LocalDateTime.now())) {
                throw new ServiceException("竞赛已经结束，不能再提交了哦");
            }
        }
        JudgeSubmitDTO judgeSubmitDTO = getJudgeSubmitDTO(userSubmitDTO);

        //调用判题服务 计算分数
//        R<JudgeResult> judgeResultR = remoteJudgeService.doJudge(judgeSubmitDTO, SecurityConstants.INNER);
//        if (R.isError(judgeResultR) || judgeResultR == null || judgeResultR.getData() == null) {
//            log.error("用户：{}，提交内容：{}，判题结果异常", SecurityUtils.getUserId(), judgeSubmitDTO);
//        } else {
//            JudgeResult judgeResult = judgeResultR.getData();
//            userSubmit.setScore(judgeResult.getScore());
//        }
        //存入rabbitMQ等待消费
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String message = objectMapper.writeValueAsString(judgeSubmitDTO);  //向mq发送消息
            judgeProducer.produceJudgeMsg(message);
            return true;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("提交参数异常", e);
        }
    }

    @Override
    public QuestionResult questionResult(Long examId, Long questionId, String currentTime) {
        UserSubmit userSubmit = userSubmitMapper.selectCurrentUserSubmit(SecurityUtils.getUserId(), examId, questionId, currentTime);

//                .selectOne(new LambdaQueryWrapper<UserSubmit>()
//                .select(UserSubmit::getSubmitId, UserSubmit::getPass, UserSubmit::getErrorMessage)
//                .eq(examId != null, UserSubmit::getExamId, examId)
//                .eq(UserSubmit::getQuestionId, questionId)
//                .eq(UserSubmit::getUserId, SecurityUtils.getUserId())
//                .ge(UserSubmit::getCreateTime, currentTime));
        QuestionResult questionResult = new QuestionResult();
        if (userSubmit == null || userSubmit.getSubmitId() == null) {
            //为获取到提交记录，说明judge服务未处理提交请求
            questionResult.setQuestionResult(QuestResultCode.UN_HANDLED.getValue());
        } else {
            questionResult.setQuestionResult(userSubmit.getPass());
            questionResult.setErrorMessage(userSubmit.getErrorMessage());
            if (!StringUtils.isEmpty(userSubmit.getCaseJudgeRes())) {
                List<CaseJudgeResult> caseJudgeResultList =
                        JSON.parseArray(userSubmit.getCaseJudgeRes(), CaseJudgeResult.class);
                questionResult.setCaseJudgeResultList(caseJudgeResultList);
            }
        }
        return questionResult;
    }

    private JudgeSubmitDTO getJudgeSubmitDTO(UserSubmitDTO userSubmitDTO) {
        UserSubmit userSubmit = new UserSubmit();
        BeanUtils.copyProperties(userSubmitDTO, userSubmit);
        userSubmit.setUserId(SecurityUtils.getUserId());
        QuestionESVO questionESVO = questionRepository
                .findById(userSubmit.getQuestionId()).orElse(null);
        JudgeSubmitDTO judgeSubmitDTO = new JudgeSubmitDTO();
        if (questionESVO != null) {
            BeanUtils.copyProperties(questionESVO, judgeSubmitDTO);
        } else {
            Question question = questionMapper.selectById(userSubmitDTO.getQuestionId());
            BeanUtils.copyProperties(question, judgeSubmitDTO);
            questionESVO = new QuestionESVO();
            BeanUtils.copyProperties(question, questionESVO);
            questionESVO.setQuestionId(question.getQuestionId());
            questionRepository.save(questionESVO);
        }
        judgeSubmitDTO.setRabbitMsgId(UUIDUtils.randomUUID());
        judgeSubmitDTO.setExamId(userSubmit.getExamId());
        judgeSubmitDTO.setQuestionId(userSubmit.getQuestionId());
        judgeSubmitDTO.setUserId(SecurityUtils.getUserId());
        judgeSubmitDTO.setUserCode(userSubmit.getUserCode());
        judgeSubmitDTO.setProgramType(userSubmit.getProgramType());
        return judgeSubmitDTO;
    }
}
